package com.durian.base.utils

import android.app.Application
import android.content.pm.ApplicationInfo
import android.os.Process
import android.os.SystemClock
import androidx.activity.ComponentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.durian.base.frame.ActivityStack
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import java.util.*
import kotlin.concurrent.thread


object XDebugger : LifecycleEventObserver {

    private var isRunning = false

    /**
     * 检测是否在非Debug编译模式下，进行了调试操作，以防动态调试
     */
    fun startCheck(activity: ComponentActivity, sleep: Long = 1000, open: Boolean = true,logBlock : (()->Unit)? = null) {
        if (sleep < 1000 || sleep > 10000 || !open) {
            return
        }
        if (isDebuggable(activity.application)) {
            ActivityStack.create().AppExit()
            return
        }
        isRunning = true
        activity.lifecycle.addObserver(this)
        thread(name = "debugger_dog") {
            while (isRunning) {
                try {
                    SystemClock.sleep(sleep)
                    if (isDebuggable(activity.application)) {
                        isRunning = false
                        ActivityStack.create().AppExit()
                    } else if (isUnderTraced()) {
                        isRunning = false
                        ActivityStack.create().AppExit()
                    }
                    logBlock?.invoke()
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
    }

    /**
     * 判断当前应用是否是debug状态
     */
    private fun isDebuggable(application: Application): Boolean {
        var result = false
        try {
            result = application.applicationInfo.let {
                it.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return result
    }


    /**
     * 当我们使用Ptrace方式跟踪一个进程时，目标进程会记录自己被谁跟踪，可以查看/proc/pid/status看到这个信息,而没有被调试的时候TracerPid为0
     * @return
     */
    private fun isUnderTraced(): Boolean {
        val processStatusFilePath: String =
            java.lang.String.format(Locale.US, "/proc/%d/status", Process.myPid())
        val procInfoFile = File(processStatusFilePath)
        try {
            val b = BufferedReader(FileReader(procInfoFile))
            var readLine: String
            while (b.readLine().also { readLine = it } != null) {
                if (readLine.contains("TracerPid")) {
                    val arrays = readLine.split(":").toTypedArray()
                    if (arrays.size == 2) {
                        val tracerPid = arrays[1].trim { it <= ' ' }.toInt()
                        if (tracerPid != 0) {
                            return true
                        }
                    }
                }
            }
            b.close()
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
        return false
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            source.lifecycle.removeObserver(this)
            isRunning = false
        }
    }
}